﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DGZImp.Core.Services;
using DGZImp.MdsProject.Devices.Models;
using Nomad.Iot.Profinet.Melsec;

namespace DGZImp.MdsProject.Devices.Base
{
    public class MelsecServe : PlcServe, IDisposable
    {
        private CancellationTokenSource _cancellationTokenSource;
        private CancellationToken _cancellationToken;

        public MelsecMcNet Plc { get; set; }

        public override event PlcDataReceiveHandler OnPlcDataReceive;
        public override event HttpDataReceiveHandler OnHttpDataReceive;
        public override event TcpDataReceiveHandler OnTcpDataReceive;
        public override event WebSocketDataReceiveHandler OnWebSocketDataReceive;

        public MelsecServe(string id, string name, string ip, int port, List<DbBlockCfgItem> dbBlocks, bool isAutoRead = true, int readInterval = 300)
        {
            Id = id;
            Name = name;
            Ip = ip;
            Port = port;
            DbBlocks = dbBlocks;
            IsAutoRead = isAutoRead;
            ReadInterval = readInterval;
            Plc = new MelsecMcNet(ip, port);
            _cancellationTokenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationTokenSource.Token;
            StartReadingAsync().ConfigureAwait(false);
        }

        public override async Task StartReadingAsync()
        {
            while (!_cancellationToken.IsCancellationRequested)
            {
                var datas = new ConcurrentDictionary<string, byte[]>();
                await Task.Delay(ReadInterval, _cancellationToken);
                if (!IsAutoRead)
                {
                    continue;
                }
                try
                {
                    foreach (var item in DbBlocks)
                    {
                        var res = await Plc.ReadAsync(item.DbBlock, item.Length);
                        if (res.IsSuccess)
                        {
                            datas.TryAdd(item.DbBlock, res.Content);
                        }
                        else
                        {
                            datas.TryRemove(item.DbBlock, out _);
                            //SysLogger.LogError($"读取{Name}[{Ip}:{Port}]数据块{item.DbBlock}失败：{res.Message}");
                            continue;
                        }
                    }
                    Datas = datas;
                    OnPlcDataReceive?.Invoke(this, datas);
                }
                catch (OperationCanceledException)
                {
                    // 处理取消请求
                }
                catch (Exception e)
                {
                    SysLogger.LogError(e, $"PLC服务{Id}读取数据失败");
                    OnPlcDataReceive?.Invoke(this, datas);
                }
            }
        }

        public override void Dispose()
        {
            _cancellationTokenSource.Cancel();
            _cancellationTokenSource.Dispose();
            Plc?.Dispose();
        }
    }
}
